// Purpose.  Proxy design pattern
// 1. Create a "wrapper" for a remote, or expensive, or sensitive target
// 2. Encapsulate the complexity/overhead of the target in the wrapper
// 3. The client deals with the wrapper
// 4. The wrapper delegates to the target
// 5. To support plug-compatibility of wrapper and target, create an interface

import java.io.*;   
import java.net.*;

interface SocketInterface {                // 5. To support plug-compatibility 
   String getMessage();                      //    between the wrapper and the
   void   sendMessage( String str );         //    target, create an interface
   void   dispose(); 
}

// net proxy for client side
class ClientNetProxy implements SocketInterface {  
   private Socket         socket;            
   private BufferedReader in;                
   private PrintWriter    out;

   public ClientNetProxy( String host, int port ) {
      try {
         socket = new Socket( host, port );  
         in  = new BufferedReader( new InputStreamReader(socket.getInputStream()));
         out = new PrintWriter( socket.getOutputStream(), true );
      } catch(java.net.ConnectException e) {
    	  socket = null;
    	  in = null;
    	  out = null;
      } catch( IOException e ) { e.printStackTrace(); }

   }
   
   public String getMessage() {
      String str = null;
      try { 
    	  if (in != null)
    		  str = in.readLine();
      } catch( IOException e ) { e.printStackTrace(); }
      return str;
   }
   
   public boolean isValid() {
	   return socket != null && in != null && out != null;
   }
   
   
   public void sendMessage( String str ) {
	   
	  if(out != null)
		  out.println( str );
	  
   }
   public void dispose() {
      try { 
    	  sendMessage("close");
    	  if( socket != null) {
    		  socket.close();
    		  socket = null;
    		  in = null;
    		  out = null;
    	  }
      } catch( IOException e ) { e.printStackTrace(); }
   }  
}

// net proxy for server side
class ServerNetProxy implements SocketInterface {
	private ServerSocket servSocket;
	private Socket socket; 
	private BufferedReader in; 
	private PrintWriter out;
	
	String connected_ip;

	public ServerNetProxy(int port) {
		try {
			servSocket = new ServerSocket( port );
		} catch ( IOException e ) { e.printStackTrace(); }
	}
	
	public void accept() {
		
		try {
			socket = servSocket.accept();
			
			connected_ip = socket.getInetAddress().getHostAddress();
			
			in  = new BufferedReader( new InputStreamReader(socket.getInputStream()));
			out = new PrintWriter( socket.getOutputStream(), true );	
		} catch(java.net.SocketException e) {
			// do nothing
		} catch ( IOException e ) { e.printStackTrace(); }
		
	}
	
	public boolean isValid() {
		return socket != null && in != null && out != null;
	}

	public String getMessage() {
		String str = null;
		try {
			if( in != null )
				str = in.readLine();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return str;
	}

	public void sendMessage(String str) {
		if (out != null)
			out.println(str); 
	}

	public void dispose() {
		try {
			if( socket != null ) {
				socket.close();
				socket = null;
				in = null;
				out = null;
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public void servDispose() {
		
		try {
			if( servSocket != null) {
				servSocket.close();
				servSocket = null;
				if(socket != null) {
					socket.close();
					socket = null;
				}
				in = null;
				out = null;
			}
		} catch (IOException e) {
			e.printStackTrace();
		}	
	}

}
